from quant import Order
from quant.const import OrderStatus, OrderType, Offset


class TopMaker:
    def __init__(self, markets, accounts, config):
        exchange = config['exchange']
        symbol = config['symbol']
        amount = config['amount']
        key = config['key']

        self.markets = markets
        self.exchange = exchange
        self.symbol = symbol
        self.amount = amount

        self.acc = accounts.create_account(exchange, key)
        self.init_acc()

    def init_acc(self):
        """
        添加交易对、初始化查询
        """
        self.acc.add_symbol(self.symbol)
        self.acc.api.query_position()
        self.acc.api.query_open_orders()
        self.acc.api.query_margin()
        self.acc.api.join()  # 等待查询完成

    def start(self):
        self.markets.add_market('Book', self.exchange, self.symbol)
        self.markets.subscribe_all(self.on_market_data)

    def on_market_data(self, market_data):
        book = market_data.data
        if book is None:
            print('接口已断开，等待自动重连')
            return

        bid_1, _ = book.item('bid', 1)
        ask_1, _ = book.item('ask', 1)

        pos = self.acc.position[self.symbol]
        long = pos['long']
        short = pos['short']

        order_by_type = {}
        for order in self.acc.orders.values():
            type_ = '{}{}'.format(order.side, order.offset)
            order_by_type[type_] = order

        order = order_by_type.get('buyOpen')
        amount = self.amount - long
        self.operate(order, bid_1, 'buy', amount, Offset.Open)

        order = order_by_type.get('buyClose')
        amount = short
        self.operate(order, bid_1, 'buy', amount, Offset.Close)

        order = order_by_type.get('sellOpen')
        amount = self.amount - short
        self.operate(order, ask_1, 'sell', amount, Offset.Open)

        order = order_by_type.get('sellClose')
        amount = long
        self.operate(order, ask_1, 'sell', amount, Offset.Close)

    def operate(self, pending_order, book_top, side, amount, offset):
        to_place = Order(
            symbol=self.symbol,
            side=side,
            price=book_top,
            amount=amount,
            offset=offset,
            order_type=OrderType.PostOnly,
        )

        if pending_order is None:
            if amount > 0:
                self.acc.api.place_order(to_place)
        else:
            if amount < 0:
                self.try_cancel(pending_order)
            elif pending_order.price != book_top:
                self.try_cancel(pending_order)

    def try_cancel(self, order):
        if order.status in (OrderStatus.Placing, OrderStatus.Canceling):
            return  # 订单仍在路由中，本次暂不处理
        self.acc.api.cancel_order(order)
